// 轻量可视化编辑器（父页面与 iframe 子页面通信）
// 说明：
// - 同域时：父页面会注入脚本到 iframe，启用悬浮高亮与点击选中
// - 跨域时：降级为仅监听来自子页面的 postMessage（若子页面已手动注入脚本）
// - 对外暴露启停编辑模式、更新样式、销毁等方法

export type SelectedElementInfo = {
  tagName: string
  id?: string
  classList?: string[]
  textSnippet?: string
  selector?: string
  pagePath?: string
  styles?: {
    marginTop?: string
    marginRight?: string
    marginBottom?: string
    marginLeft?: string
    borderRadius?: string
  }
}

export type IframeEditorOptions = {
  iframe: HTMLIFrameElement
  previewUrl?: string
  onHoverChange?: (info: SelectedElementInfo | null) => void
  onSelect?: (info: SelectedElementInfo) => void
}

export type IframeEditorController = {
  enable: () => void
  disable: () => void
  isEnabled: () => boolean
  applyStyle: (style: Partial<NonNullable<SelectedElementInfo['styles']>>) => void
  destroy: () => void
}

const buildSelector = (el: Element): string => {
  if (!(el instanceof Element)) return ''
  const parts: string[] = []
  let current: Element | null = el
  while (current && parts.length < 10) {
    let part = current.tagName.toLowerCase()
    if (current.id) {
      part += `#${CSS.escape(current.id)}`
      parts.unshift(part)
      break
    }
    const className = (current as HTMLElement).className?.toString().trim()
    if (className) {
      const classes = className
        .split(/\s+/)
        .filter(Boolean)
        .slice(0, 3)
        .map((c) => `.${CSS.escape(c)}`)
        .join('')
      if (classes) part += classes
    }
    const parentEl: Element | null = current.parentElement
    if (parentEl) {
      const siblings = Array.from(parentEl.children as unknown as Element[]).filter((n: Element) => (n as Element).tagName === current!.tagName)
      if (siblings.length > 1) {
        const index = siblings.indexOf(current) + 1
        part += `:nth-of-type(${index})`
      }
    }
    parts.unshift(part)
    current = parentEl
  }
  return parts.join(' > ')
}

const childInjectedScript = `
  (function () {
    if (window.__QING_IFRAME_EDITOR__) return;
    window.__QING_IFRAME_EDITOR__ = true;

    var enabled = false;
    var hoverBox = document.createElement('div');
    hoverBox.style.position = 'absolute';
    hoverBox.style.pointerEvents = 'none';
    hoverBox.style.border = '2px solid #1890ff';
    hoverBox.style.borderRadius = '4px';
    hoverBox.style.zIndex = '2147483646';
    hoverBox.style.display = 'none';

    var label = document.createElement('div');
    label.style.position = 'absolute';
    label.style.transform = 'translateY(-100%)';
    label.style.background = '#1890ff';
    label.style.color = '#fff';
    label.style.fontSize = '12px';
    label.style.padding = '2px 6px';
    label.style.borderRadius = '4px 4px 0 0';
    hoverBox.appendChild(label);

    var fixedBox = document.createElement('div');
    fixedBox.style.position = 'absolute';
    fixedBox.style.pointerEvents = 'none';
    fixedBox.style.border = '2px solid #0958d9';
    fixedBox.style.borderRadius = '4px';
    fixedBox.style.zIndex = '2147483647';
    fixedBox.style.display = 'none';

    document.documentElement.appendChild(hoverBox);
    document.documentElement.appendChild(fixedBox);

    function rectOf(el){
      var r = el.getBoundingClientRect();
      return {x:r.left + window.scrollX, y:r.top + window.scrollY, w:r.width, h:r.height}
    }

    function updateBox(el, box, showLabel){
      var r = rectOf(el);
      box.style.left = r.x + 'px';
      box.style.top = r.y + 'px';
      box.style.width = r.w + 'px';
      box.style.height = r.h + 'px';
      box.style.display = 'block';
      if (showLabel) {
        label.textContent = el.tagName.toLowerCase();
      }
    }

    function clearBox(box){
      box.style.display = 'none';
    }

    function buildSelector(el){
      try {
        var parts = [];
        var current = el;
        for (var i=0;i<10 && current;i++){
          var part = current.tagName.toLowerCase();
          if (current.id){ part += '#' + CSS.escape(current.id); parts.unshift(part); break; }
          var cn = (current.className||'').toString().trim();
          if (cn){
            var classes = cn.split(/\s+/).filter(Boolean).slice(0,3).map(function(c){return '.'+CSS.escape(c)}).join('');
            if (classes) part += classes;
          }
          var parent = current.parentElement;
          if (parent){
            var siblings = Array.prototype.filter.call(parent.children, function(n){return n.tagName === current.tagName});
            if (siblings.length>1){
              var index = Array.prototype.indexOf.call(siblings, current) + 1;
              part += ':nth-of-type(' + index + ')';
            }
          }
          parts.unshift(part);
          current = parent;
        }
        return parts.join(' > ');
      } catch(e){ return ''; }
    }

    function elementInfo(el){
      var cs = window.getComputedStyle(el);
      return {
        tagName: el.tagName.toLowerCase(),
        id: el.id || undefined,
        classList: Array.from(el.classList||[]),
        textSnippet: (el.textContent||'').trim().slice(0, 60),
        selector: buildSelector(el),
        pagePath: window.location.pathname,
        styles: {
          marginTop: cs.marginTop,
          marginRight: cs.marginRight,
          marginBottom: cs.marginBottom,
          marginLeft: cs.marginLeft,
          borderRadius: cs.borderRadius
        }
      }
    }

    var lastHoverTarget = null;
    function onMove(e){
      if(!enabled) return;
      var t = e.target;
      if(!(t instanceof Element)) return;
      lastHoverTarget = t;
      updateBox(t, hoverBox, true);
      try { parent.postMessage({ type: 'element-hover', payload: elementInfo(t) }, '*'); } catch(_){}
    }
    function onClick(e){
      if(!enabled) return;
      e.preventDefault();
      e.stopPropagation();
      var t = e.target;
      if(!(t instanceof Element)) return;
      updateBox(t, fixedBox, false);
      try { parent.postMessage({ type: 'element-selected', payload: elementInfo(t) }, '*'); } catch(_){}
    }
    function onScroll(){
      if(!enabled) return;
      if(lastHoverTarget) updateBox(lastHoverTarget, hoverBox, true);
    }

    function enable(){
      enabled = true;
      document.addEventListener('mousemove', onMove, true);
      document.addEventListener('click', onClick, true);
      window.addEventListener('scroll', onScroll, true);
    }
    function disable(){
      enabled = false;
      document.removeEventListener('mousemove', onMove, true);
      document.removeEventListener('click', onClick, true);
      window.removeEventListener('scroll', onScroll, true);
      clearBox(hoverBox); clearBox(fixedBox);
    }

    window.addEventListener('message', function(ev){
      var d = ev.data || {};
      if (!d || typeof d !== 'object') return;
      if (d.type === 'qing-editor-enable') enable();
      if (d.type === 'qing-editor-disable') disable();
      if (d.type === 'qing-editor-apply-style' && d.payload && d.payload.selector){
        try {
          var node = document.querySelector(d.payload.selector);
          if (node && node instanceof HTMLElement){
            var s = d.payload.styles || {};
            Object.keys(s).forEach(function(k){ node.style[k] = s[k]; });
          }
        } catch(_){}
      }
    });
  })();
`

export function setupIframeEditor(options: IframeEditorOptions): IframeEditorController {
  const { iframe, previewUrl, onHoverChange, onSelect } = options
  let enabled = false

  const sameOrigin = (() => {
    try {
      if (!previewUrl) return false
      const a = new URL(previewUrl, window.location.href)
      return a.origin === window.location.origin
    } catch {
      return false
    }
  })()

  // 注入脚本（同域可注入）
  const tryInject = () => {
    if (!sameOrigin) return
    try {
      const doc = iframe.contentDocument
      if (!doc) return
      const script = doc.createElement('script')
      script.type = 'text/javascript'
      script.textContent = childInjectedScript
      doc.documentElement.appendChild(script)
    } catch (e) {
      // 注入失败忽略，等待子页面自行集成
      // console.warn('iframe 注入失败:', e)
    }
  }

  const handleMessage = (event: MessageEvent) => {
    const data = event.data as any
    if (!data || typeof data !== 'object') return

    // 安全校验：若可判定来源且不同源则忽略
    if (event.origin && previewUrl) {
      try {
        const expect = new URL(previewUrl, window.location.href).origin
        if (expect !== '*' && event.origin !== expect && event.origin !== window.location.origin) {
          return
        }
      } catch {}
    }

    if (data.type === 'element-hover') {
      onHoverChange?.(data.payload as SelectedElementInfo)
    }
    if (data.type === 'element-selected') {
      onSelect?.(data.payload as SelectedElementInfo)
    }
  }

  window.addEventListener('message', handleMessage)

  const enable = () => {
    enabled = true
    tryInject()
    // 通知子页面开启
    iframe.contentWindow?.postMessage({ type: 'qing-editor-enable' }, '*')
  }
  const disable = () => {
    enabled = false
    iframe.contentWindow?.postMessage({ type: 'qing-editor-disable' }, '*')
    onHoverChange?.(null)
  }
  const isEnabled = () => enabled

  const applyStyle: IframeEditorController['applyStyle'] = (style) => {
    // 将样式应用到已选中元素（通过 selector）
    iframe.contentWindow?.postMessage({ type: 'qing-editor-apply-style', payload: { selector: lastSelected?.selector, styles: style } }, '*')
  }

  let lastSelected: SelectedElementInfo | null = null
  const originalOnSelect = onSelect
  options.onSelect = (info: SelectedElementInfo) => {
    lastSelected = info
    originalOnSelect?.(info)
  }

  // 若 iframe 已加载，尝试立即注入
  const docReady = () => {
    try {
      return iframe.contentDocument?.readyState === 'complete'
    } catch {
      return false
    }
  }
  if (docReady()) {
    tryInject()
  } else {
    iframe.addEventListener('load', tryInject, { once: true })
  }

  const destroy = () => {
    disable()
    window.removeEventListener('message', handleMessage)
  }

  return { enable, disable, isEnabled, applyStyle, destroy }
}


